home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / umich / network / ka9q / nhclb120.zoo / telunix.c < prev    next >
C/C++ Source or Header  |  1992-06-18  |  7KB  |  361 lines

  1. #include <stdio.h>
  2. #include "global.h"
  3. #include "config.h"
  4. #include "mbuf.h"
  5. #include "timer.h"
  6. #include "icmp.h"
  7. #include "netuser.h"
  8. #include "tcp.h"
  9. #include "telnet.h"
  10. #include "session.h"
  11. #ifndef _MEMORY_H
  12. char *memchr();
  13. #endif
  14. static void tnix_state();
  15. #define TUMAXSCAN 3    /* max number of telunix clients active */
  16. #define TURQSIZ    512    /* max data we will request from pty at once */
  17.  
  18. struct tcb *tnix_tcb = NULLTCB;
  19. struct tcb *tnixtcb[TUMAXSCAN];    /* savebuf for tcb ptrs for scan routines */
  20. extern int errno;
  21. #ifdef    SYS5
  22. extern unsigned long selmask;
  23. #endif
  24.  
  25. /* Start telnet-unix server */
  26. tnix1(argc,argv)
  27. char *argv[];
  28. {
  29.     struct socket lsocket;
  30.     extern int32 ip_addr;
  31.     void tnix_state();
  32.  
  33.     /* Incoming Telnet */
  34.     lsocket.address = ip_addr;
  35.  
  36.     if(argc < 2)
  37.         lsocket.port = TELNET_PORT;
  38.     else
  39.         lsocket.port = atoi(argv[1]);
  40.  
  41.     tnix_tcb = open_tcp(&lsocket,NULLSOCK,TCP_SERVER,0,
  42.             NULLVFP,NULLVFP,tnix_state,0,(char *)NULL);
  43.  
  44.     if(tnix_tcb == NULLTCB)
  45.         fprintf(stderr,"start telunix fails rsn %d.\n",net_error);
  46.     else
  47.         log(tnix_tcb,"STARTED Telunix - (%d %x)",
  48.             lsocket.port,tnix_tcb);
  49. }
  50.  
  51. /* Shut down Telnet server */
  52. tnix0()
  53. {
  54.     if(tnix_tcb != NULLTCB) {
  55.         log(tnix_tcb,"STOPPED Telunix - (%x)",tnix_tcb);
  56.         close_tcp(tnix_tcb);
  57.     } else
  58.         fprintf(stderr,"stop telunix fails -- no server active.\n");
  59. }
  60.  
  61. /* Handle incoming Telnet-Unix connect requests */
  62. static void
  63. tnix_state(tcb,old,new)
  64. struct tcb *tcb;
  65. char old,new;
  66. {
  67.     register struct telnet *tn;
  68.     int tnix_addscan();
  69.     extern void tnix_rmvscan();
  70.     extern int send_tcp();
  71.     extern struct mbuf *free_p();
  72.     extern int del_tcp();
  73.     extern int close_tcp();
  74. #ifdef    SYS5
  75. #ifndef free
  76.     extern void free();
  77. #endif
  78. #endif
  79.  
  80.     tn = (struct telnet *)tcb->user;
  81.  
  82.     switch(new){
  83.     case ESTABLISHED:
  84.         /* Create and initialize a Telnet protocol descriptor */
  85.         if((tn = (struct telnet *)calloc(1,sizeof(struct telnet))) == NULLTN){
  86.             log(tcb,"reject Telunix - no space");
  87.             sndmsg(tcb,"Rejected; no space on remote\n");
  88.             close_tcp(tcb);
  89.             return;
  90.         }
  91.         tn->session = NULLSESSION;
  92.         tn->state = TS_DATA;
  93.         tcb->user = (char *)tn;    /* Upward pointer */
  94.         tn->tcb = tcb;        /* Downward pointer */
  95.         tn->inbuf = NULLBUF;
  96.         tn->outbuf = NULLBUF;
  97.         if(tnix_addscan(tcb) < 0 ||
  98.            (tn->fd = OpenPty()) < 3) {    /* barf if <= stderr */
  99.             tnix_rmvscan(tcb);
  100.             log(tcb,"reject Telunix - no Unix ports");
  101.             sndmsg(tcb,
  102.                 "Rejected; no ports available on remote\n");
  103.             close_tcp(tcb);
  104.             return;
  105.         }
  106. #ifdef    SYS5
  107.         selmask |= (1 << tn->fd);
  108. #endif
  109.         log(tcb,"open Telunix - (%d %x %d %d)",tn->fd,tcb,old,new);
  110.         break;
  111.  
  112.     case FINWAIT1:
  113.     case FINWAIT2:
  114.     case CLOSING:
  115.     case LAST_ACK:
  116.     case TIME_WAIT:
  117.         if(tn != NULLTN &&
  118.            tn->fd > 2) {
  119.             log(tcb,"close Telunix - (%d %x %d %d)",
  120.                 tn->fd,tcb,old,new);
  121.             close(tn->fd);
  122. #ifdef    SYS5
  123.             selmask &=  ~(1 << tn->fd);
  124. #endif
  125.             tn->fd = 0;
  126.         }
  127.         tnix_rmvscan(tcb);
  128.         break;
  129.  
  130.     case CLOSE_WAIT:
  131.         /* flush that last buffer */
  132.         if(tn != NULLTN &&
  133.            tn->outbuf != NULLBUF &&
  134.            tn->outbuf->cnt != 0) {
  135.             send_tcp(tcb,tn->outbuf);
  136.             tn->outbuf = NULLBUF;
  137.         }
  138.         close_tcp(tcb);
  139.         break;
  140.     
  141.     case CLOSED:
  142.         if(tn != NULLTN) {
  143.             if(tn->fd > 2) {
  144.                 log(tcb,"close Telunix - (%d %x %d %d)",
  145.                     tn->fd,tcb,old,new);
  146.                 close(tn->fd);
  147. #ifdef    SYS5
  148.                 selmask &=  ~(1 << tn->fd);
  149. #endif
  150.                 tn->fd = 0;
  151.             }
  152.             if(tn->inbuf != NULLBUF)
  153.                 free_p(tn->inbuf);
  154.             if(tn->outbuf != NULLBUF)
  155.                 free_p(tn->outbuf);
  156.             free((char *)tn);
  157.         }
  158.         tnix_rmvscan(tcb);
  159.         del_tcp(tcb);
  160.         if(tcb == tnix_tcb)
  161.             tnix_tcb = NULLTCB;
  162.         break;
  163.     }
  164. }
  165.  
  166. /* Telunix io interface.  Called periodically to process any waiting io.  */
  167. void
  168. tnix_try(tcb)
  169. register struct tcb *tcb;
  170. {
  171.     extern void tnix_rmvscan();
  172.     extern int recv_tcp();
  173.     extern int send_tcp();
  174.     extern void tnix_input();
  175.  
  176.     register struct telnet *tn;
  177.     register int i;
  178.  
  179.     if((tn = (struct telnet *)tcb->user) == NULLTN || tn->fd < 3) {
  180.         /* Unknown connection - remove it from queue */
  181.         log(tcb,"error Telnet - tnix_try (%d)", tn);
  182.         tnix_rmvscan(tcb);
  183.         return;
  184.     }
  185.     /*
  186.      * First, check if there is any pending io for the pty:
  187.      */
  188.     if(tn->inbuf != NULLBUF) {
  189.         tnix_input(tn);
  190.     }
  191.     if(tn->inbuf == NULLBUF) {
  192.         if(tcb->rcvcnt > 0 &&
  193.            recv_tcp(tcb,&(tn->inbuf),0) > 0)
  194.             tnix_input(tn);
  195.     }
  196.     /*
  197.      * Next, check if there is any io for tcp:
  198.      */
  199.     do {
  200.         if(tn->outbuf == NULLBUF &&
  201.            (tn->outbuf = alloc_mbuf(TURQSIZ)) == NULLBUF)
  202.             return;        /* can't do much without a buffer */
  203.     
  204.         if(tn->outbuf->cnt < TURQSIZ) {
  205.             if((i = read(tn->fd, tn->outbuf->data + tn->outbuf->cnt,
  206.                 (int)(TURQSIZ - tn->outbuf->cnt))) == -1) {
  207.                 log(tcb,"error Telunix - read (%d %d %d)",
  208.                     errno, tn->fd,
  209.                     TURQSIZ - tn->outbuf->cnt);
  210.                 close_tcp(tcb);
  211.                 return;
  212.             }
  213.             if((tn->outbuf->cnt += i) < TURQSIZ)
  214.                 i = 0;    /* didn't fill buffer so don't retry */
  215.         } else {
  216.             i = -1;        /* any nonzero value will do */
  217.         }
  218.         if(tn->outbuf->cnt == 0 ||    /* nothing to send */
  219.            tcb->sndcnt > tcb->window)    /* too congested to send */
  220.             return;
  221.         if(send_tcp(tcb,tn->outbuf) < 0) {
  222.             log(tcb,"error Telunix - send_tcp (%d %d %d)",
  223.                 net_error, tn->fd, tn->outbuf->cnt);
  224.             close_tcp(tcb);
  225.             tn->outbuf = NULLBUF;
  226.             return;
  227.         }
  228.         tn->outbuf = NULLBUF;
  229.     } while(i);
  230. }
  231.  
  232. /* Process incoming TELNET characters */
  233. void
  234. tnix_input(tn)
  235. register struct telnet *tn;
  236. {
  237.     void doopt(),dontopt(),willopt(),wontopt(),answer();
  238.  
  239.     register int i;
  240.     register struct mbuf *bp;
  241.     char c;
  242.  
  243.     bp = tn->inbuf;
  244.  
  245.     /* Optimization for very common special case -- no special chars */
  246.     if(tn->state == TS_DATA){
  247.         while(bp != NULLBUF &&
  248.               memchr(bp->data,IAC,(int)bp->cnt) == NULLCHAR) {
  249.             if((i = write(tn->fd, bp->data, (int)bp->cnt)) == bp->cnt) {
  250.                 tn->inbuf = bp = free_mbuf(bp);
  251.             } else if(i == -1) {
  252.                 log(tn->tcb,"error Telunix - write (%d %d %d)",
  253.                     errno, tn->fd, bp->cnt);
  254.                 close_tcp(tn->tcb);
  255.                 return;
  256.             } else {
  257.                 bp->cnt -= i;
  258.                 bp->data += i;
  259.                 return;
  260.             }
  261.         }
  262.         if(bp == NULLBUF)
  263.             return;
  264.     }
  265.     while(pullup(&(tn->inbuf),&c,1) == 1){
  266.         bp = tn->inbuf;
  267.         switch(tn->state){
  268.         case TS_DATA:
  269.             if(uchar(c) == IAC){
  270.                 tn->state = TS_IAC;
  271.             } else {
  272.                 if(!tn->remote[TN_TRANSMIT_BINARY])
  273.                     c &= 0x7f;
  274.                 if(write(tn->fd, &c, 1) != 1) {
  275.                     /* we drop a character here */
  276.                     return;
  277.                 }
  278.             }
  279.             break;
  280.         case TS_IAC:
  281.             switch(uchar(c)){
  282.             case WILL:
  283.                 tn->state = TS_WILL;
  284.                 break;
  285.             case WONT:
  286.                 tn->state = TS_WONT;
  287.                 break;
  288.             case DO:
  289.                 tn->state = TS_DO;
  290.                 break;
  291.             case DONT:
  292.                 tn->state = TS_DONT;
  293.                 break;
  294.             case IAC:
  295.                 if(write(tn->fd, &c, 1) != 1) {
  296.                     /* we drop a character here */
  297.                     return;
  298.                 }
  299.                 tn->state = TS_DATA;
  300.                 break;
  301.             default:
  302.                 tn->state = TS_DATA;
  303.                 break;
  304.             }
  305.             break;
  306.         case TS_WILL:
  307.             willopt(tn,c);
  308.             tn->state = TS_DATA;
  309.             break;
  310.         case TS_WONT:
  311.             wontopt(tn,c);
  312.             tn->state = TS_DATA;
  313.             break;
  314.         case TS_DO:
  315.             doopt(tn,c);
  316.             tn->state = TS_DATA;
  317.             break;
  318.         case TS_DONT:
  319.             dontopt(tn,c);
  320.             tn->state = TS_DATA;
  321.             break;
  322.         }
  323.     }
  324. }
  325.  
  326. /* called periodically from main loop */
  327. void
  328. tnix_scan()
  329. {
  330.     void tnix_try();
  331.     register int i;
  332.  
  333.     for(i = 0; i < TUMAXSCAN; i += 1)
  334.         if(tnixtcb[i] != NULLTCB)
  335.             tnix_try(tnixtcb[i]);
  336. }
  337.  
  338. int
  339. tnix_addscan(tcb)
  340. struct tcb *tcb;
  341. {
  342.     register int i;
  343.     for(i = 0; i < TUMAXSCAN; i += 1)
  344.         if(tnixtcb[i] == NULLTCB) {
  345.             tnixtcb[i] = tcb;
  346.             return i;
  347.         }
  348.     return -1;
  349. }
  350.  
  351. void
  352. tnix_rmvscan(tcb)
  353. struct tcb *tcb;
  354. {
  355.     register int i;
  356.  
  357.     for(i = 0; i < TUMAXSCAN; i += 1)
  358.         if(tnixtcb[i] == tcb)
  359.             tnixtcb[i] = NULLTCB;
  360. }
  361.